package com.bbzn.device.client.service.impl;

import com.bbzn.device.client.vo.req.AuditVO;
import com.bbzn.device.client.constant.AuditConstant;
import com.bbzn.device.client.dataobject.*;
import com.bbzn.device.client.dto.audit.LeaveFormDTO;
import com.bbzn.device.client.exception.DefinitException;
import com.bbzn.device.client.service.*;
import com.bbzn.device.client.utils.OptionalBean;
import com.bbzn.device.client.utils.PageInfo;
import com.bbzn.user.client.UserClient;
import com.bbzn.user.comment.User;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import com.bbzn.device.client.dao.audit.LeaveFormMapper;

@Service
public class LeaveFormServiceImpl implements LeaveFormService{

    @Resource
    private LeaveFormMapper leaveFormMapper;

    @Autowired
    private UserClient userClient;

    @Autowired
    private SystemParamByCacheService systemParamByCacheService;

    @Autowired
    private LeaveFormService leaveFormService;

    @Autowired
    private ProcessFlowService processFlowService;

    @Autowired
    private FlowNodeService flowNodeService;

    @Autowired
    private FlowService flowService;

    @Autowired
    private AuditNoticeService auditNoticeService;

    @Override
    public int deleteByPrimaryKey(Long formId) {
        return leaveFormMapper.deleteByPrimaryKey(formId);
    }

    @Override
    public int insert(LeaveForm record) {
        return leaveFormMapper.insert(record);
    }

    @Override
    public int insertOrUpdate(LeaveForm record) {
        return leaveFormMapper.insertOrUpdate(record);
    }

    @Override
    public int insertOrUpdateSelective(LeaveForm record) {
        return leaveFormMapper.insertOrUpdateSelective(record);
    }

    @Override
    public int insertSelective(LeaveForm record) {
        return leaveFormMapper.insertSelective(record);
    }

    @Override
    public LeaveForm selectByPrimaryKey(Long formId) {
        return leaveFormMapper.selectByPrimaryKey(formId);
    }

    @Override
    public int updateByPrimaryKeySelective(LeaveForm record) {
        return leaveFormMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(LeaveForm record) {
        return leaveFormMapper.updateByPrimaryKey(record);
    }

    @Override
    public List<LeaveForm> findByAll(LeaveForm leaveForm) {
        return leaveFormMapper.findByAll(leaveForm);
    }

    @Override
    public int updateBatch(List<LeaveForm> list) {
        return leaveFormMapper.updateBatch(list);
    }

    @Override
    public int updateBatchSelective(List<LeaveForm> list) {
        return leaveFormMapper.updateBatchSelective(list);
    }

    @Override
    public int batchInsert(List<LeaveForm> list) {
        return leaveFormMapper.batchInsert(list);
    }

    @Override
    public PageInfo<LeaveForm> selectPageBySelective(LeaveFormDTO record) {
        PageInfo<LeaveForm> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(record.getPageNum());
        pageInfo.setPageSize(record.getPageSize());
        pageInfo.setResultList(leaveFormMapper.selectPageBySelective(record));
        int count = leaveFormMapper.selectCountBySelective(record);
        pageInfo.setTotalRecord(count);
        return pageInfo;
    }

    @Override
    public int selectCountBySelective(LeaveFormDTO record) {
        return leaveFormMapper.selectCountBySelective(record);
    }

    @Override
    public void createLeaveFrom(AuditVO reqVO,Long userId,String language) throws Exception {
        //1.持久化form表单数据,8级以下员工表单状态为processing,8级(总经理)状态为approved
        SystemParam systemParam = null;
        LeaveForm form = new LeaveForm();
        if(reqVO.getFlowNodeLevel()==2){
            form.setState(1);
        }else{
            form.setState(0);
        }
        User user = userClient.selectByPrimaryKey(userId);
        if (!OptionalBean.ofNullable(user).isPresent()) {
            systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_CUS_PREFIX + language);
            throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
        }
        form.setApplyUserName(user.getUsername());
        form.setApplyUserPhone(user.getPhone());
        form.setAddress(reqVO.getAddress());
        form.setCreateTime(new Date());
        form.setUserId(userId);
        form.setStartTime(reqVO.getStartTime());
        form.setEndTime(reqVO.getEndTime());
        form.setFormType(reqVO.getFormType());
        form.setReason(reqVO.getReason());
        form.setUserId(userId);
        leaveFormService.insertSelective(form);
        //3.分情况创建其余流程数据
        //3.1 被监管人,生成监管人审批任务,请假时间大于72小时,还需生成租户审批任务
        Flow flow = flowService.selectByPrimaryKey(reqVO.getFlewId());
        if(null==flow){
            systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_FLEW_PREFIX + language);
            throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
        }
        createProcess(userId,flow,form,user,language);
    }


    private void createProcess(Long userId,Flow flow,LeaveForm form,User user,String language) throws Exception {
        SystemParam systemParam= null;
        FlowNode query = new FlowNode();
        query.setFlowId(flow.getFlowId());
        List<FlowNode> flowNodes = flowNodeService.findByAll(query);
        int i = 1;
        for (FlowNode flowNode : flowNodes) {
            if(userId==flowNode.getFlowNodeUserId() && i==1) {
                i=flowNode.getFlowNodeLevel();
            }
            userId = flowNodes.get(i-1).getFlowNodeUserId();
            User userLevel = userClient.selectByPrimaryKey(flowNodes.get(i-1).getFlowNodeUserId());
            if (!OptionalBean.ofNullable(userLevel).isPresent()) {
                systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_CUS_PREFIX + language);
                throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
            }
            if(flowNodes.get(i-1).getFlowNodeLevel()==i){
                ProcessFlow flowi = new ProcessFlow();
                flowi.setFormId(form.getFormId());
                flowi.setOperatorId(flowNodes.get(i-1).getFlowNodeUserId());
                flowi.setOperatorName(userLevel.getUsername());
                flowi.setAction(1);
                flowi.setCreateTime(new Date());
                flowi.setOrderNo(flow.getOrderNo());
                flowi.setState(1);
                if(i<=2){
                    flowi.setIsLast(0);
                    form.setAgentId(flowNodes.get(i-1).getFlowNodeUserId());
                }else if (i==3){
                    flowi.setIsLast(1);
                    form.setManangeId(flowNodes.get(i-1).getFlowNodeUserId());
                }
                processFlowService.insertSelective(flowi);
            }
            i++;
        }
    }


    @Override
    public void auditLeaveFrom(AuditVO record, Long userId, String language) throws Exception {
        SystemParam systemParam = null;
        //1.无论同意/驳回,当前任务状态变更为complete
        ProcessFlow flow = new ProcessFlow();
        flow.setFormId(record.getFormId());
        List<ProcessFlow> flowList = processFlowService.findByAll(flow);
        if(CollectionUtils.isEmpty(flowList)){
            systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_FLEW_PREFIX + language);
            throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
        }
        //获取当前任务ProcessFlow对象
        List<ProcessFlow> processList = flowList.stream().filter(p -> p.getOperatorId().equals(userId) && p.getState()<2).collect(Collectors.toList());
        ProcessFlow process = null;
        if(CollectionUtils.isEmpty(processList)){
            systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_DEAL_FLEW_PREFIX + language);
            throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
        }else{
            process = processList.get(0);
            process.setState(2);
            process.setResult(record.getResult());
            process.setReason(record.getReason());
            process.setAuditTime(new Date());
            processFlowService.updateByPrimaryKeySelective(process);
        }
        LeaveForm form = leaveFormService.selectByPrimaryKey(record.getFormId());
        Flow oneFlow = flowService.findOneByOrderNo(process.getOrderNo());
        FlowNode query  = new FlowNode();
        query.setFlowId(oneFlow.getFlowId());
        List<FlowNode> flowNodes = flowNodeService.findByAll(query);
        Long oneUserId = flowNodes.stream().filter(flowNode -> flowNode.getFlowNodeLevel() == 2).map(FlowNode::getFlowNodeUserId).findFirst().orElseThrow(() -> new DefinitException(-1, "Data is null"));
        Long twoUserId = flowNodes.stream().filter(flowNode -> flowNode.getFlowNodeLevel() == 3).map(FlowNode::getFlowNodeUserId).findFirst().orElseThrow(() -> new DefinitException(-1, "Data is null"));
        User oneUser = userClient.selectByPrimaryKey(oneUserId);
        User twoUser = userClient.selectByPrimaryKey(twoUserId);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH时");
        String noticeContent = null;
        AuditNotice notice = new AuditNotice();
        notice.setCreateTime(new Date());
        //2.如果当前任务是最后一个节点,代表流程结束,更新请假单状态为对应的approved/refused
        if(process.getIsLast() == 1){
            form.setState(record.getResult());//approved|refused
            leaveFormService.updateByPrimaryKey(form);

            String strResult = null;
            if(record.getResult()==1){
                strResult = "批准";
            }else if (record.getResult()==2){
                strResult = "驳回";
            }

            if(record.getFlowNodeLevel()==2){
                noticeContent = String.format("请假申请[%s-%s]已%s,审批意见:%s,审批流程已结束" ,
                        sdf.format( form.getStartTime()) , sdf.format(form.getEndTime()),
                        strResult , record.getResult());//发给审批人的通知
                notice.setContent(noticeContent);
                notice.setProcessFlowId(process.getProcessId());
                notice.setReceiverId(oneUser.getId());
            }
            if(record.getFlowNodeLevel()==3){
                noticeContent = String.format("提起请假申请[%s-%s]已%s,审批意见:%s,审批流程已结束" ,
                        sdf.format( form.getStartTime()) , sdf.format(form.getEndTime()),
                        strResult , record.getResult());//发给审批人的通知
                notice.setContent(noticeContent);
                notice.setProcessFlowId(process.getProcessId());
                notice.setReceiverId(userId);
            }
            auditNoticeService.insertSelective(notice);
        }else{
            //readyList包含所有后续任务节点
            List<ProcessFlow> readyList = flowList.stream().filter(p -> p.getState()<2).sorted(Comparator.comparing(ProcessFlow::getProcessId)).collect(Collectors.toList());
            //3.如果当前任务不是最后一个节点且审批通过,那下一个节点的状态从ready变为process
            if(record.getResult()==1){
                if(readyList.size()>1 && null!=readyList.get(1)){
                    ProcessFlow readyProcess = readyList.get(1);
                    readyProcess.setState(1);
                    processFlowService.updateByPrimaryKeySelective(readyProcess);
                }
                //消息3: 通知部门经理(当前经办人),员工的申请单你已批准,交由上级继续审批
                if(record.getFlowNodeLevel()==2){
                    String noticeContent3 = String.format("提起请假申请[%s-%s]已批准,审批意见:%s,申请转至上级领导继续审批" ,
                            sdf.format( form.getStartTime()) , sdf.format(form.getEndTime()), record.getResult());
                    notice.setContent(noticeContent3);
                    notice.setProcessFlowId(process.getProcessId());
                    if(null!=oneUser){
                        notice.setReceiverId(oneUser.getId());
                    }else{
                        notice.setReceiverId(userId);
                    }
                    auditNoticeService.insertSelective(notice);
                }
                if (!OptionalBean.ofNullable(twoUser).isPresent()) {
                    systemParam = systemParamByCacheService.getValues(AuditConstant.AUDIT_ENUM, AuditConstant.AUDIT_NO_TNTUSER_PREFIX + language);
                    throw new DefinitException(systemParam.getCode(), systemParam.getMassage());
                }
                form.setUserId(twoUser.getId());
                form.setAgentId(oneUser.getId());
                leaveFormService.updateByPrimaryKeySelective(form);
            }else if(record.getResult()==2) {
                //4.如果当前任务不是最后一个节点且审批驳回,则后续所有任务状态变为cancel,请假单状态变为refused
                for(ProcessFlow p:readyList){
                    p.setState(3);
                    processFlowService.updateByPrimaryKeySelective(p);
                }
                form.setState(2);
                leaveFormService.updateByPrimaryKeySelective(form);
//                消息1: 通知申请人表单已被驳回
                String noticeContent1 = String.format("请假申请[%s-%s]已驳回,审批意见:%s,审批流程已结束" ,
                        sdf.format(form.getStartTime()) , sdf.format(form.getEndTime()),
                        record.getResult());
                notice.setContent(noticeContent1);
                notice.setProcessFlowId(process.getProcessId());
                notice.setReceiverId(oneUser.getId());
                auditNoticeService.insertSelective(notice);
            }
        }
    }
}
